using System;
using System.Collections;
using System.Collections.Generic;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;

namespace OracleInternal.BinXml
{
	internal class ObxmlTokenMap
	{
		private static ulong m_Nsidnull;

		private static ulong m_Nsidxi;

		internal static List<ObxmlToken> m_NsTokenList;

		internal static List<ObxmlToken> m_AttrTokenList;

		private TokenTypes m_DefaultTokenType = TokenTypes.ElementToken;

		private bool m_bInit;

		private ObxmlTokenManagerContext m_tmContext;

		private CacheWithLRUList<ulong, ObxmlToken> m_ElementAttributeTokens;

		private CacheWithLRUList<ulong, ObxmlToken> m_NamespaceTokens;

		private Hashtable m_NamespaceUriTokens = new Hashtable();

		internal string PartitionId;

		internal bool IsActive;

		internal string TokenMapSizeString => string.Empty;

		internal ulong NSIDNULL => m_Nsidnull;

		internal ulong NSIDXI => m_Nsidxi;

		static ObxmlTokenMap()
		{
			m_Nsidnull = 0uL;
			m_Nsidxi = 0uL;
			m_NsTokenList = new List<ObxmlToken>(8);
			m_AttrTokenList = new List<ObxmlToken>(7);
			m_NsTokenList.Add(CreateObxmlNamespaceToken(1uL, "http://www.w3.org/XML/1998/namespace"));
			m_NsTokenList.Add(CreateObxmlNamespaceToken(2uL, "http://www.w3.org/XML/2000/xmlns/"));
			m_NsTokenList.Add(CreateObxmlNamespaceToken(3uL, "http://www.w3.org/2001/XMLSchema-instance"));
			m_NsTokenList.Add(CreateObxmlNamespaceToken(4uL, "http://www.w3.org/2001/XMLSchema"));
			m_NsTokenList.Add(CreateObxmlNamespaceToken(5uL, "http://xmlns.oracle.com/2004/csx"));
			m_NsTokenList.Add(CreateObxmlNamespaceToken(6uL, "http://xmlns.oracle.com/xdb"));
			m_NsTokenList.Add(CreateObxmlNamespaceToken(7uL, ""));
			m_NsTokenList.Add(CreateObxmlNamespaceToken(8uL, "http://www.w3.org/2001/XInclude"));
			m_AttrTokenList.Add(CreateObxmlQNameToken(16uL, 1uL, "space", isAttribute: true));
			m_AttrTokenList.Add(CreateObxmlQNameToken(17uL, 1uL, "lang", isAttribute: true));
			m_AttrTokenList.Add(CreateObxmlQNameToken(18uL, 3uL, "type", isAttribute: true));
			m_AttrTokenList.Add(CreateObxmlQNameToken(19uL, 3uL, "nil", isAttribute: true));
			m_AttrTokenList.Add(CreateObxmlQNameToken(20uL, 3uL, "schemaLocation", isAttribute: true));
			m_AttrTokenList.Add(CreateObxmlQNameToken(21uL, 3uL, "noNamespaceSchemaLocation", isAttribute: true));
			m_AttrTokenList.Add(CreateObxmlQNameToken(22uL, 2uL, "xmlns", isAttribute: true));
		}

		internal ObxmlTokenMap()
		{
			Init();
		}

		internal ObxmlTokenMap(ObxmlTokenManagerContext context, TokenTypes tokenType)
		{
			m_DefaultTokenType = tokenType;
			PartitionId = context.PartitionId;
			m_tmContext = context;
			Init();
		}

		internal void Clear()
		{
			if (m_ElementAttributeTokens != null)
			{
				m_ElementAttributeTokens.Purge();
			}
			if (m_NamespaceTokens != null)
			{
				m_NamespaceTokens.Purge();
			}
			if (m_NamespaceUriTokens != null)
			{
				m_NamespaceUriTokens.Clear();
			}
		}

		internal ObxmlTokenManagerContext GetTokenMgrContext()
		{
			return m_tmContext;
		}

		internal bool Init()
		{
			if (m_bInit)
			{
				return true;
			}
			if (m_ElementAttributeTokens == null)
			{
				m_ElementAttributeTokens = new CacheWithLRUList<ulong, ObxmlToken>(ObxmlTokenManager.MaxTokenPoolEntries);
			}
			if (m_NamespaceTokens == null)
			{
				m_NamespaceTokens = new CacheWithLRUList<ulong, ObxmlToken>(ObxmlTokenManager.MaxTokenPoolEntries / 100);
			}
			m_ElementAttributeTokens.Put(16uL, m_AttrTokenList[0]);
			m_ElementAttributeTokens.Put(17uL, m_AttrTokenList[1]);
			m_ElementAttributeTokens.Put(18uL, m_AttrTokenList[2]);
			m_ElementAttributeTokens.Put(19uL, m_AttrTokenList[3]);
			m_ElementAttributeTokens.Put(20uL, m_AttrTokenList[4]);
			m_ElementAttributeTokens.Put(21uL, m_AttrTokenList[5]);
			m_ElementAttributeTokens.Put(22uL, m_AttrTokenList[6]);
			m_NamespaceTokens.Put(1uL, m_NsTokenList[0]);
			m_NamespaceTokens.Put(2uL, m_NsTokenList[1]);
			m_NamespaceTokens.Put(3uL, m_NsTokenList[2]);
			m_NamespaceTokens.Put(4uL, m_NsTokenList[3]);
			m_NamespaceTokens.Put(5uL, m_NsTokenList[4]);
			m_NamespaceTokens.Put(6uL, m_NsTokenList[5]);
			m_NamespaceTokens.Put(7uL, m_NsTokenList[6]);
			m_NamespaceTokens.Put(8uL, m_NsTokenList[7]);
			m_NamespaceUriTokens[m_NsTokenList[0].TokenName] = m_NsTokenList[0];
			m_NamespaceUriTokens[m_NsTokenList[1].TokenName] = m_NsTokenList[1];
			m_NamespaceUriTokens[m_NsTokenList[2].TokenName] = m_NsTokenList[2];
			m_NamespaceUriTokens[m_NsTokenList[3].TokenName] = m_NsTokenList[3];
			m_NamespaceUriTokens[m_NsTokenList[4].TokenName] = m_NsTokenList[4];
			m_NamespaceUriTokens[m_NsTokenList[5].TokenName] = m_NsTokenList[5];
			m_NamespaceUriTokens[m_NsTokenList[6].TokenName] = m_NsTokenList[6];
			m_NamespaceUriTokens[m_NsTokenList[7].TokenName] = m_NsTokenList[7];
			ulong namespaceTokenId = GetNamespaceTokenId(null);
			m_Nsidnull = m_NamespaceTokens.Get(namespaceTokenId).TokenId;
			namespaceTokenId = GetNamespaceTokenId("http://www.w3.org/2001/XInclude");
			m_Nsidxi = m_NamespaceTokens.Get(namespaceTokenId).TokenId;
			return m_bInit = true;
		}

		internal string GetPartitionId()
		{
			return PartitionId;
		}

		internal void SetToken(ObxmlToken token)
		{
			if (token == null)
			{
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.TokenInvalid));
			}
			switch (token.TokenType)
			{
			case TokenTypes.ElementToken:
				if (!m_ElementAttributeTokens.ContainsKey(token.TokenId))
				{
					m_ElementAttributeTokens.Put(token.TokenId, token);
				}
				break;
			case TokenTypes.AttributeToken:
				if (!m_ElementAttributeTokens.ContainsKey(token.TokenId))
				{
					m_ElementAttributeTokens.Put(token.TokenId, token);
				}
				break;
			case TokenTypes.NamespaceToken:
				if (!m_NamespaceTokens.ContainsKey(token.TokenId))
				{
					RegisterNamespace(token);
				}
				break;
			default:
				throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.TokenInvalid));
			}
		}

		internal ObxmlToken PopulateNamespaceUri(ObxmlDecodeContext decodeContext, ObxmlToken token)
		{
			if (token != null && token.NamespaceId == m_Nsidnull)
			{
				token.NamespaceId = 0uL;
			}
			if (token.NamespaceId != 0L && token.Uri == null)
			{
				token.Uri = GetNamespaceToken(decodeContext, token.NamespaceId)?.TokenName;
			}
			return token;
		}

		internal string GetTokenNameForDefaultTokenType(ObxmlDecodeContext decodeContext, ulong tokenId)
		{
			try
			{
				ObxmlToken tokenForDefaultTokenType = GetTokenForDefaultTokenType(decodeContext, tokenId);
				if (tokenForDefaultTokenType != null)
				{
					return tokenForDefaultTokenType.TokenName;
				}
			}
			catch (Exception)
			{
			}
			return null;
		}

		internal ObxmlToken ConvertNSIDToNullNameSpaceId(ObxmlDecodeContext decodeContext, ObxmlToken token, bool tryBothIds = false)
		{
			if (token != null)
			{
				if (tryBothIds && token.TokenType == TokenTypes.NamespaceToken && token.TokenId == m_Nsidnull)
				{
					token.TokenId = 0uL;
				}
				if (token.NamespaceId == m_Nsidnull)
				{
					token.NamespaceId = 0uL;
				}
				if (decodeContext.DbConnection.m_oracleConnectionImpl.m_NamespaceTokens.Count < decodeContext.DbConnection.m_oracleConnectionImpl.m_NamespaceTokens.m_maxCacheSize && token.TokenType == TokenTypes.NamespaceToken)
				{
					decodeContext.DbConnection.m_oracleConnectionImpl.m_NamespaceTokens.Put(token.TokenId, token);
				}
				else if (decodeContext.DbConnection.m_oracleConnectionImpl.m_ElementAttributeTokens.Count < decodeContext.DbConnection.m_oracleConnectionImpl.m_ElementAttributeTokens.m_maxCacheSize && (TokenTypes.ElementToken == token.TokenType || TokenTypes.AttributeToken == token.TokenType))
				{
					decodeContext.DbConnection.m_oracleConnectionImpl.m_ElementAttributeTokens.Put(token.TokenId, token);
				}
			}
			return token;
		}

		internal ObxmlToken GetTokenForDefaultTokenType(ObxmlDecodeContext decodeContext, ulong tokenId)
		{
			return GetToken(decodeContext, tokenId, m_DefaultTokenType);
		}

		internal ObxmlToken GetToken(ObxmlDecodeContext decodeContext, ulong tokenId, TokenTypes tokenType, bool tryRepository = true)
		{
			ObxmlToken obxmlToken = null;
			try
			{
				switch (tokenType)
				{
				case TokenTypes.AttributeToken:
				case TokenTypes.ElementToken:
					obxmlToken = decodeContext.DbConnection.m_oracleConnectionImpl.m_ElementAttributeTokens.Get(tokenId);
					if (obxmlToken != null)
					{
						return obxmlToken;
					}
					obxmlToken = m_ElementAttributeTokens.Get(tokenId);
					break;
				case TokenTypes.NamespaceToken:
					obxmlToken = decodeContext.DbConnection.m_oracleConnectionImpl.m_NamespaceTokens.Get(tokenId);
					if (obxmlToken != null)
					{
						return obxmlToken;
					}
					obxmlToken = m_NamespaceTokens.Get(tokenId);
					break;
				case TokenTypes.PrefixToken:
					break;
				}
			}
			catch
			{
			}
			if (obxmlToken == null && tryRepository)
			{
				decodeContext.MetaDataRepository.GetTokenSet(decodeContext, tokenId, tokenType, null, null, bPopulateTokenMap: true);
				return GetToken(decodeContext, tokenId, tokenType, tryRepository: false);
			}
			ConvertNSIDToNullNameSpaceId(decodeContext, obxmlToken);
			return obxmlToken;
		}

		internal static bool TryGetValue(CacheWithLRUList<ulong, ObxmlToken> tokenCache, ulong key, out ObxmlToken value)
		{
			if (tokenCache.ContainsKey(key))
			{
				value = tokenCache.Get(key);
				return true;
			}
			value = null;
			return false;
		}

		internal ObxmlToken GetToken(ObxmlDecodeContext decodeContext, ulong tokenId, bool tryRepository)
		{
			try
			{
				ObxmlToken value = null;
				if (TryGetValue(decodeContext.DbConnection.m_oracleConnectionImpl.m_ElementAttributeTokens, tokenId, out value) && value != null)
				{
					return value;
				}
				if (TryGetValue(decodeContext.DbConnection.m_oracleConnectionImpl.m_NamespaceTokens, tokenId, out value) && value != null)
				{
					return value;
				}
				if (TryGetValue(m_ElementAttributeTokens, tokenId, out value) && value != null)
				{
					ConvertNSIDToNullNameSpaceId(decodeContext, value);
					return value;
				}
				if (TryGetValue(m_NamespaceTokens, tokenId, out value) && value != null)
				{
					ConvertNSIDToNullNameSpaceId(decodeContext, value);
					return value;
				}
				if (tryRepository)
				{
					decodeContext.MetaDataRepository.GetTokenSet(decodeContext, tokenId, TokenTypes.ElementToken, null, null, bPopulateTokenMap: true);
					value = GetToken(decodeContext, tokenId, tryRepository: false);
					if (value == null)
					{
						decodeContext.MetaDataRepository.GetTokenSet(decodeContext, tokenId, TokenTypes.NamespaceToken, null, null, bPopulateTokenMap: true);
						return GetToken(decodeContext, tokenId, tryRepository: false);
					}
					if (value != null)
					{
						ConvertNSIDToNullNameSpaceId(decodeContext, value);
						return value;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		internal string GetTokenName(ObxmlDecodeContext decodeContext, ulong tokenId, TokenTypes tokenType)
		{
			try
			{
				return GetToken(decodeContext, tokenId, tokenType)?.TokenName;
			}
			catch (Exception)
			{
			}
			return null;
		}

		internal string GetTokenName(ObxmlDecodeContext decodeContext, ulong tokenId)
		{
			try
			{
				return GetToken(decodeContext, tokenId, tryRepository: true)?.TokenName;
			}
			catch (Exception)
			{
			}
			return null;
		}

		internal void RegisterNamespace(ObxmlToken token)
		{
			if (!m_NamespaceTokens.ContainsKey(token.TokenId))
			{
				m_NamespaceTokens.Put(token.TokenId, token);
			}
			if (!m_NamespaceUriTokens.ContainsKey(token.TokenName))
			{
				m_NamespaceUriTokens.Add(token.TokenName, token);
			}
		}

		internal string GetNamespaceUri(ObxmlDecodeContext decodeContext, ulong nsid, out ObxmlToken token)
		{
			token = null;
			string result = string.Empty;
			if (nsid == 0L)
			{
				return result;
			}
			token = GetNamespaceToken(decodeContext, nsid);
			if (token != null)
			{
				result = token.TokenName;
			}
			return result;
		}

		internal ObxmlToken GetNamespaceToken(ObxmlDecodeContext decodeContext, ulong nsid, TokenTypes tokenType = TokenTypes.NamespaceToken)
		{
			return GetToken(decodeContext, nsid, tokenType);
		}

		internal static ObxmlToken CreateObxmlToken(ulong tokenId, string tokenName, TokenTypes tokenType = TokenTypes.None)
		{
			if (tokenType == TokenTypes.None)
			{
				tokenType = TokenTypes.ElementToken;
			}
			ObxmlToken obxmlToken = new ObxmlToken(tokenId, tokenName, tokenType);
			if (obxmlToken != null && obxmlToken.NamespaceId == m_Nsidnull)
			{
				obxmlToken.NamespaceId = 0uL;
			}
			return obxmlToken;
		}

		internal ObxmlToken CreateToken(ulong tokenId, string tokenName, TokenTypes tokenType = TokenTypes.None)
		{
			ObxmlToken obxmlToken = CreateObxmlToken(tokenId, tokenName, tokenType);
			SetToken(obxmlToken);
			return obxmlToken;
		}

		internal static ObxmlToken CreateObxmlNamespaceToken(ulong tokenId, string namespaceURI)
		{
			return CreateObxmlToken(tokenId, namespaceURI, TokenTypes.NamespaceToken);
		}

		internal ObxmlToken CreateNamespaceToken(ulong tokenId, string namespaceURI)
		{
			ObxmlToken obxmlToken = CreateObxmlNamespaceToken(tokenId, namespaceURI);
			SetToken(obxmlToken);
			return obxmlToken;
		}

		internal static ObxmlToken CreateObxmlQNameToken(ulong tokenId, ulong namespaceId, string localName, bool isAttribute)
		{
			ObxmlToken obxmlToken = CreateObxmlToken(tokenId, localName, isAttribute ? TokenTypes.AttributeToken : TokenTypes.ElementToken);
			if (namespaceId == m_Nsidnull)
			{
				obxmlToken.NamespaceId = 0uL;
			}
			else
			{
				obxmlToken.NamespaceId = namespaceId;
			}
			return obxmlToken;
		}

		internal ObxmlToken CreateQNameToken(ulong tokenId, ulong namespaceId, string localName, bool isAttribute)
		{
			ObxmlToken obxmlToken = CreateObxmlQNameToken(tokenId, namespaceId, localName, isAttribute);
			SetToken(obxmlToken);
			return obxmlToken;
		}

		internal ObxmlToken PutNamespaceNonSchema(string namespaceURI)
		{
			ObxmlToken obxmlToken = null;
			if (namespaceURI == null)
			{
				return m_NsTokenList[6];
			}
			obxmlToken = (ObxmlToken)m_NamespaceUriTokens[namespaceURI];
			if (obxmlToken != null)
			{
				return obxmlToken;
			}
			throw new OracleException(ResourceStringConstants.XML_TYPE_BINARY_INTERNAL_ERROR, string.Empty, string.Empty, ObxmlDecodeResponse.GetErrorMessage(ObxmlErrorTypes.NotImplemented));
		}

		internal ulong GetNamespaceTokenId(string namespaceURI)
		{
			ObxmlToken obxmlToken = null;
			if (!string.IsNullOrEmpty(namespaceURI))
			{
				obxmlToken = (ObxmlToken)m_NamespaceUriTokens[namespaceURI];
			}
			if (obxmlToken == null)
			{
				obxmlToken = PutNamespaceNonSchema(namespaceURI);
			}
			return obxmlToken.TokenId;
		}
	}
}
